package com.kmxd.ams.app.system;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.kmxd.ams.client.system.ISysDictItemSvc;
import com.kmxd.ams.client.system.dto.SysDictItemAddDTO;
import com.kmxd.ams.client.system.dto.SysDictItemEditDTO;
import com.kmxd.ams.client.system.dto.SysDictItemQueryDTO;
import com.kmxd.ams.client.system.vo.SysDictItemListVO;
import com.kmxd.ams.client.system.vo.SysDictItemVO;
import com.kmxd.ams.core.common.constant.CacheConst;
import com.kmxd.ams.core.common.constant.ErrorCode;
import com.kmxd.ams.core.exception.BizTipException;
import com.kmxd.ams.core.util.IdUtil;
import com.kmxd.ams.infra.system.entity.SysDictItem;
import com.kmxd.ams.infra.system.mapper.SysDictItemMapper;
import java.util.*;
import lombok.AllArgsConstructor;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * 字典项 服务实现类
 *
 * @author admin
 * @since 2021-06-10
 */
@Service
@AllArgsConstructor
public class SysDictItemSvcImpl extends ServiceImpl<SysDictItemMapper, SysDictItem>
    implements ISysDictItemSvc {

  private SysDictItemMapper sysDictItemMapper;

  @Override
  public Page<SysDictItemListVO> selectPage(Page reqPage, SysDictItemQueryDTO req) {
    if (Objects.isNull(req.getDictId())) {
      Page<SysDictItemListVO> page = new Page<>();
      return page;
    }
    LambdaQueryWrapper<SysDictItem> queryWrapper = Wrappers.lambdaQuery();
    queryWrapper.eq(Objects.nonNull(req.getDictId()), SysDictItem::getDictId, req.getDictId());
    queryWrapper.eq(Objects.nonNull(req.getSetCode()), SysDictItem::getSetCode, req.getSetCode());
    queryWrapper.like(
        StrUtil.isNotBlank(req.getDictItemCode()),
        SysDictItem::getDictItemCode,
        Optional.ofNullable(req.getDictItemCode()).orElse("").toLowerCase());
    queryWrapper.like(
        StrUtil.isNotBlank(req.getDictItemName()),
        SysDictItem::getDictItemName,
        req.getDictItemName());
    queryWrapper.orderByAsc(SysDictItem::getSort);
    Page<SysDictItem> page = sysDictItemMapper.selectPage(reqPage, queryWrapper);
    Page<SysDictItemListVO> voPage = BeanUtil.copyProperties(page, Page.class);
    voPage.setRecords(BeanUtil.copyToList(page.getRecords(), SysDictItemListVO.class));
    return voPage;
  }

  @Override
  public List<SysDictItemListVO> selectList(SysDictItemQueryDTO req) {
    if (Objects.isNull(req.getDictId())) {
      return new ArrayList();
    }
    LambdaQueryWrapper<SysDictItem> queryWrapper = Wrappers.lambdaQuery();
    queryWrapper.eq(Objects.nonNull(req.getDictId()), SysDictItem::getDictId, req.getDictId());
    queryWrapper.like(
        StrUtil.isNotBlank(req.getDictItemCode()),
        SysDictItem::getDictItemCode,
        Optional.ofNullable(req.getDictItemCode()).orElse("").toLowerCase());
    queryWrapper.like(
        StrUtil.isNotBlank(req.getDictItemName()),
        SysDictItem::getDictItemName,
        req.getDictItemName());
    queryWrapper.eq(
        StrUtil.isNotBlank(req.getSetCode()), SysDictItem::getSetCode, req.getSetCode());
    queryWrapper.orderByAsc(SysDictItem::getSort);
    List<SysDictItem> list = sysDictItemMapper.selectList(queryWrapper);
    return BeanUtil.copyToList(list, SysDictItemListVO.class);
  }

  @Override
  public List<SysDictItemListVO> selectListAll() {
    LambdaQueryWrapper<SysDictItem> queryWrapper = Wrappers.lambdaQuery();
    queryWrapper.orderByAsc(SysDictItem::getSort);
    List<SysDictItem> list = sysDictItemMapper.selectList(queryWrapper);
    return BeanUtil.copyToList(list, SysDictItemListVO.class);
  }

  @CacheEvict(value = CacheConst.CACHE_PREFIX_SYS_DICT, allEntries = true)
  @Override
  @Transactional(rollbackFor = Exception.class)
  public void add(SysDictItemAddDTO req) {
    if (!this.checkUniqueDictItemName(
        req.getDictItemName(), null, req.getDictId(), req.getSetCode(), req.getVersion())) {
      throw BizTipException.instance(ErrorCode.VALIDATE_ERROR, "字典项名称已存在");
    }
    if (!this.checkUniqueDictItemCode(
        req.getDictItemCode(), null, req.getDictId(), req.getSetCode(), req.getVersion())) {
      throw BizTipException.instance(ErrorCode.VALIDATE_ERROR, "字典项编码已存在");
    }
    SysDictItem entity = BeanUtil.copyProperties(req, SysDictItem.class);
    sysDictItemMapper.insert(entity);
  }

  @CacheEvict(value = CacheConst.CACHE_PREFIX_SYS_DICT, allEntries = true)
  @Override
  @Transactional(rollbackFor = Exception.class)
  public void edit(SysDictItemEditDTO req) {
    if (!this.checkUniqueDictItemName(
        req.getDictItemName(), req.getId(), req.getDictId(), req.getSetCode(), req.getVersion())) {
      throw BizTipException.instance(ErrorCode.VALIDATE_ERROR, "字典项名称已存在");
    }
    if (!this.checkUniqueDictItemCode(
        req.getDictItemCode(), req.getId(), req.getDictId(), req.getSetCode(), req.getVersion())) {
      throw BizTipException.instance(ErrorCode.VALIDATE_ERROR, "字典项编码已存在");
    }
    SysDictItem entity = BeanUtil.copyProperties(req, SysDictItem.class);
    sysDictItemMapper.updateById(entity);
  }

  @CacheEvict(value = CacheConst.CACHE_PREFIX_SYS_DICT, allEntries = true)
  @Override
  @Transactional(rollbackFor = Exception.class)
  public void remove(String ids) {
    Set<Long> idList = IdUtil.split(ids);
    sysDictItemMapper.deleteBatchIds(idList);
  }

  @Override
  public void removeByDictId(Long dictId) {
    sysDictItemMapper.delete(
        Wrappers.<SysDictItem>lambdaQuery().eq(SysDictItem::getDictId, dictId));
  }

  @Override
  public SysDictItemVO view(Long id) {
    SysDictItem entity = sysDictItemMapper.selectById(id);
    return BeanUtil.copyProperties(entity, SysDictItemVO.class);
  }

  private Boolean checkUniqueDictItemName(
      String value, Long id, Long dictId, String setCode, Integer version) {
    if (StrUtil.isBlank(value)) {
      return true;
    }
    id = Objects.isNull(id) ? -1L : id;
    SysDictItem entity =
        sysDictItemMapper.selectOne(
            Wrappers.lambdaQuery(SysDictItem.class)
                .eq(SysDictItem::getDictItemName, value)
                .eq(ObjectUtil.isNotNull(setCode), SysDictItem::getSetCode, setCode.toLowerCase())
                .eq(ObjectUtil.isNotNull(version), SysDictItem::getVersion, version)
                .eq(SysDictItem::getDictId, dictId));
    return Objects.isNull(entity) || NumberUtil.equals(entity.getId(), id);
  }

  private Boolean checkUniqueDictItemCode(
      String value, Long id, Long dictId, String setCode, Integer version) {
    if (StrUtil.isBlank(value)) {
      return true;
    }
    id = Objects.isNull(id) ? -1L : id;
    SysDictItem entity =
        sysDictItemMapper.selectOne(
            Wrappers.lambdaQuery(SysDictItem.class)
                .eq(SysDictItem::getDictItemCode, value.toLowerCase())
                .eq(ObjectUtil.isNotNull(setCode), SysDictItem::getSetCode, setCode.toLowerCase())
                .eq(ObjectUtil.isNotNull(version), SysDictItem::getVersion, version)
                .eq(SysDictItem::getDictId, dictId));
    return Objects.isNull(entity) || NumberUtil.equals(entity.getId(), id);
  }
}
